package com.kexuexiong.file.oss.impl;

import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelFileUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.UploadFileRequest;
import com.aliyun.oss.model.UploadFileResult;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.profile.DefaultProfile;
import com.google.gson.Gson;
import com.kexuexiong.file.oss.OssService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * <p>功能描述</p>
 *
 * @author xy
 * @version 1.0
 * @ClassName OssService.java
 * @date 2021年11月2021/11/30日 10:58
 */
@Service("ossService")
@Slf4j
public class OssServiceImpl implements OssService {

    private static String endpoint = "https://oss-cn-beijing.aliyuncs.com";
    private static String accessKeyId = "LTAI5tJgWsckNdQYcCTFTeiw";
    private static String accessKeySecret = "MQhc89soZN7OThyzkAZ398Xkh72RjK";
    private static String bucketName = "fresh-fruit";
    private static String key = "<downloadKey>";
    private static String uploadFile = "E:\\2021-02\\generator-develop.zip";

    /**
     * 获取sts权限
     * 参考url：
     *
     * @return
     */
    @Override
    public AssumeRoleResponse getSTSToken() {
        //构建一个阿里云客户端，用于发起请求。
        //构建阿里云客户端时需要设置AccessKey ID和AccessKey Secret。
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "LTAI5t5ZiLyUwzZUG1nfCYQH", "cDjpemY96SyWEUpy5jO4okislyaXCo");
        IAcsClient client = new DefaultAcsClient(profile);

        //构造请求，设置参数。关于参数含义和设置方法，请参见API参考。
        AssumeRoleRequest request = new AssumeRoleRequest();
        request.setRegionId("cn-beijing");
        request.setRoleArn("acs:ram::1632881681687749:role/ramosstest");
        request.setRoleSessionName("ramosstest");
        //发起请求，并得到响应。
        try {
            AssumeRoleResponse response = client.getAcsResponse(request);
            System.out.println(new Gson().toJson(response));
            return response;
        } catch (ServerException e) {
            e.printStackTrace();
            return null;
        } catch (com.aliyuncs.exceptions.ClientException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 私有获取文件，需要sts权限控制
     */
    @Override
    public void authorizationGetFile() {
        AssumeRoleResponse roleResponse = getSTSToken();
        if (Objects.isNull(roleResponse)) {
            log.error("request:{}", JSONUtil.toJsonStr(roleResponse));
            return;
        }
        // 从STS服务获取的临时访问密钥（AccessKey ID和AccessKey Secret）。
        String accessKeyId = roleResponse.getCredentials().getAccessKeyId();
        String accessKeySecret = roleResponse.getCredentials().getAccessKeySecret();
        // 从STS服务获取的安全令牌（SecurityToken）。
        String securityToken = roleResponse.getCredentials().getSecurityToken();
        // 填写Object完整路径，例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
        String objectName = "20211103b18f9e1d-879a-4c72-b242-6c8f1591e59a.png";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);

        // 设置签名URL过期时间为3600秒（1小时）。
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
        URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration);
        System.out.println(url);
        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * oss上传文件
     */
    @Override
    public void uploadFile() {
        key = UUID.randomUUID().toString();
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            UploadFileRequest uploadFileRequest = new UploadFileRequest(bucketName, key);
            // The local file to upload---it must exist.
            uploadFileRequest.setUploadFile(uploadFile);
            // Sets the concurrent upload task number to 5.
            uploadFileRequest.setTaskNum(5);
            // Sets the part size to 1MB.
            uploadFileRequest.setPartSize(1024 * 1024 * 1);
            // Enables the checkpoint file. By default it's off.
            uploadFileRequest.setEnableCheckpoint(true);
            UploadFileResult uploadResult = ossClient.uploadFile(uploadFileRequest);
            log.info("upload-file:{}", JSONUtil.toJsonStr(uploadResult));
        } catch (Exception oe) {
            oe.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            ossClient.shutdown();
        }
    }

    @Override
    public String authorizationGetFileByFileKey(String fileKey) throws IOException {
        AssumeRoleResponse roleResponse = getSTSToken();
        if (Objects.isNull(roleResponse)) {
            log.error("request:{}", JSONUtil.toJsonStr(roleResponse));
            return "";
        }
        // 从STS服务获取的临时访问密钥（AccessKey ID和AccessKey Secret）。
        String accessKeyId = roleResponse.getCredentials().getAccessKeyId();
        String accessKeySecret = roleResponse.getCredentials().getAccessKeySecret();
        // 从STS服务获取的安全令牌（SecurityToken）。
        String securityToken = roleResponse.getCredentials().getSecurityToken();
        // 填写Object完整路径，例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
        String objectName = fileKey;

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);

        // 设置签名URL过期时间为3600秒（1小时）。
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
        URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration);
        String filePath = "D:\\downloadFile\\" + fileKey;
        //下载到本地
        try (BufferedInputStream bufferedInputStream = new BufferedInputStream(url.openStream());
             FileOutputStream fileOutputStream = new FileOutputStream(filePath)) {
            byte[] buffer = new byte[1024];
            int count = 0;
            while ((count = bufferedInputStream.read(buffer, 0, 1024)) != -1) {
                fileOutputStream.write(buffer, 0, count);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(url);
        // 关闭OSSClient。
        ossClient.shutdown();
        return filePath;
    }

    /**
     * oss上传文件
     */
    @Override
    public void uploadFileByFileKey(String uploadFile) {
        //先对本地的excel进行添加uuid
        String destFilePath = "D:\\downloadFile\\copy-" + UUID.randomUUID(true).toString().replace("-", "") + ".xlsx";
        try (ExcelReader reader = ExcelUtil.getReader(FileUtil.file(uploadFile), 0);
             ExcelWriter writer = ExcelUtil.getWriter(destFilePath)) {
            List<Map<String, Object>> read = reader.read(0, 1, 1000);
            for (int i = 0; i < read.size(); i++) {
                Map<String, Object> stringObjectMap = read.get(i);
                stringObjectMap.put("UUID", UUID.randomUUID(true).toString().replace("-", ""));
            }
            writer.write(read, true);
        } catch (Exception e) {
            e.printStackTrace();
        }

        key = "copy-"+UUID.randomUUID();

        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            UploadFileRequest uploadFileRequest = new UploadFileRequest(bucketName, key);
            // The local file to upload---it must exist.
            uploadFileRequest.setUploadFile(uploadFile);
            // Sets the concurrent upload task number to 5.
            uploadFileRequest.setTaskNum(5);
            // Sets the part size to 1MB.
            uploadFileRequest.setPartSize(1024 * 1024 * 1);
            // Enables the checkpoint file. By default it's off.
            uploadFileRequest.setEnableCheckpoint(true);
            UploadFileResult uploadResult = ossClient.uploadFile(uploadFileRequest);
            log.info("upload-file:{}", JSONUtil.toJsonStr(uploadResult));
        } catch (Exception oe) {
            oe.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            ossClient.shutdown();
        }
    }

    @Override
    public String uploadFileByFilePath(String filePath, String fileKey) {
        key = fileKey+"-"+UUID.randomUUID();
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            UploadFileRequest uploadFileRequest = new UploadFileRequest(bucketName, key);
            // The local file to upload---it must exist.
            uploadFileRequest.setUploadFile(filePath);
            // Sets the concurrent upload task number to 5.
            uploadFileRequest.setTaskNum(5);
            // Sets the part size to 1MB.
            uploadFileRequest.setPartSize(1024 * 1024 * 1);
            // Enables the checkpoint file. By default it's off.
            uploadFileRequest.setEnableCheckpoint(true);
            UploadFileResult uploadResult = ossClient.uploadFile(uploadFileRequest);
            log.info("upload-file:{}", JSONUtil.toJsonStr(uploadResult));
        } catch (Exception oe) {
            oe.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            ossClient.shutdown();
            return key;
        }
    }

    @Override
    public List<Map<String, Object>> getExcelDataListPage(String fileKey, Integer pageNo, Integer pageSize) throws IOException {
        //通过fileKey获取oss中文件
        String filePath = this.authorizationGetFileByFileKey(fileKey);
        ExcelReader reader = ExcelUtil.getReader(FileUtil.file(filePath), 0);
        //获取第一行表头
        List<List<Object>> list = reader.read(0, 0);
        List<List<Object>> read = reader.read((pageNo - 1) * pageSize + 1, pageNo * pageSize);
        list.addAll(read);
        log.info("数据为：{}", JSONUtil.toJsonStr(list));

        List<Map<String, Object>> mapList = reader.read(0, (pageNo - 1) * pageSize + 1, pageNo * pageSize);
        log.info("包含表头的数据：{}", mapList);
        //最后要删除
        File file = FileUtil.file(filePath);
        boolean delete = file.delete();
        log.info("删除文件：{}", delete);
        return mapList;
    }

    public static void main(String[] args) throws IOException {
        OssServiceImpl ossService = new OssServiceImpl();
        ossService.uploadFileByFileKey("C:\\Users\\admin\\Desktop\\服务次数0的会员数据.xlsx");
//        StopWatch stopWatch = new StopWatch();
//        stopWatch.start("查询excel");
//        OssServiceImpl ossService = new OssServiceImpl();
//        ossService.getExcelDataListPage("服务次数0的会员数据.xlsx",1,10);
//        stopWatch.stop();
//        log.info("耗时情况：{}", stopWatch.prettyPrint());
    }
}
